03 软件双缓冲
1 采样不能等串口
FFT主课先停下来处理一帧,是为了便于验证。真正连续采集时,ADC还在不断产生新数据,CPU必须在数据被覆盖前处理完。
设8 kHz采样,一个数组512个半字,分成前后各256点。DMA写后半区时,CPU处理前半区;DMA绕回前半区时,CPU处理后半区。每次只有32 ms可用。
F103C8T6的DMA通道没有两个内存地址寄存器组成的硬件双缓冲,本方案是循环DMA加半传输/传输完成中断。
2 CubeMX配置与工作顺序
沿用FFT实验的TIM3触发、ADC1单通道与DMA连接,但本页预算采用8 kHz:TIM3时钟72 MHz、PSC=71、ARR=124,区别于原工程5 kHz的ARR=199。把DMA模式改成Circular循环模式,数组长度改为512;两端仍为Half Word,内存自增,开启DMA1 Channel1中断。
前256点写满 → 半传输回调 → CPU处理前半区 / DMA写后半区
后256点写满 → 完成回调 → CPU处理后半区 / DMA写前半区
回调只登记“哪一半完成”,不要在其中运行FFT、滤波或串口打印。
3 数据比标志位更重要
最容易犯的错误是只用一个 ready = 1。CPU来不及处理时,第二次事件把第一次覆盖了,程序看起来还在运行,但数据已经不连续。
可靠的实现至少要满足:
- 用递增的完成序号记录每次半缓冲完成,主循环比较序号差,检测错过的块。
- 在下一次DMA进入该半区之前完成读取或复制,关CPU中断也不会停止DMA。
- 复制完再次检查完成序号和DMA当前位置;若时间边界被跨过,丢弃这一帧并记录错误。
这里的关键不是“越多缓冲越好”,若平均处理速度比数据到达速度慢,最终仍然会满。初学时先用单帧版测出耗时,再决定是否进入连续版。
4 把时间先算出来
| 项目 | 本课程例子 |
|---|---|
| 每半缓冲时间 | 256 / 8000 = 32 ms |
| 可用CPU周期 | 72 MHz × 32 ms = 2304000 cycles |
| 原始16位数据流 | 8000 × 2 = 16000 byte/s |
| 115200、8N1理论有效字节率 | 115200 / 10 = 11520 byte/s |
所以115200波特率连完整的二进制原始流都传不完,更不要说每个点转成十进制文本。可只发主峰和幅度,或降低采样率、抽取显示数据、提高实际可用串口带宽。抽取作为信号降采样时,先做抗混叠低通;单纯少显示一些点不能视作严格的信号重采样。
可以在处理函数前后翻转一个空闲GPIO,用示波器测量高电平宽度,记录最坏耗时。
6 工程验收
连续运行并记录最大处理耗时、ADC极值和UART拥塞情况。只有采样稳定、没有覆盖、输出带宽充足,频谱和滤波结果才有意义。